package jdict;

import java.io.*;

public class BlockFile
{
    InputStream in;
    int block_id;
    int blocksize;
    int block_offset;
    int abs_offset;
    String basename;
    boolean useMarks;

    int filesize;

    public void read_block_size()
    {
        InputStream bfile = getClass().getResourceAsStream("/dicts/BLOCKSIZE");
        /* 10 bytes is enough for a simple int */
        byte array[] = new byte[10];
        int total;
        try {
            total = bfile.read(array, 0, 10);
        } catch (IOException e)
        {
            System.out.println("Cannot open BLOCKS file. Going to 32000 B.");
            blocksize = 32000;
            return;
        }
        /* This will have '\n' */
        String str = new String(array, 0, total - 1 /* - \n */);
        blocksize = Integer.parseInt(str);
        /*
        System.out.println("Block size: " +
                new Integer(blocksize).toString());
                */
        filesize = 0;
    }

    void enableMarks()
    {
        if (in.markSupported())
        {
            System.out.println("Enabling Marks");
            useMarks = true;
            openIndex(0);
        }
    }

    public int get_block_size()
    {
        return blocksize;
    }

    public int get_file_size()
    {
        return filesize;
    }

    public void set_file_size(int size)
    {
        filesize = size;
    }

    public BlockFile(String _basename)
    {
        read_block_size();
        basename = _basename;
        useMarks = false;
        openIndex(0);
    }

    public String int2char(int val)
    {
        String result;
        if (val <= 9)
            result =  "00" + new Integer(val).toString();
        else if (val <= 99)
            result =  "0" + new Integer(val).toString();
        else
            result = new Integer(val).toString();
        return result;
    }

    public int getAbsPos()
    {
        return abs_offset;
    }

    public void seekFromStart(int bytes) throws IOException
    {
        int new_block_id;
        boolean seeked = false;

        new_block_id = bytes / blocksize;

        if (useMarks && new_block_id == block_id)
        {
            seeked = true;
            try {
                in.reset();
            } catch (IOException e)
            {
                System.out.println("in reset() failed.");
                seeked = false;
            }
        }
        if (seeked == false)
        {
            openIndex(new_block_id); /* This overwrites block_offset and id*/
        }
        block_offset = bytes - new_block_id*blocksize;

        /*
        System.out.println("Seek to block_id " +
                new Integer(block_id).toString() +
                " and block_offset " +
                new Integer(block_offset).toString());
                */

        if (in == null)
            throw new IOException("Out of file bounds");
        in.skip(block_offset);
        abs_offset = bytes;
    }

    public void skip(int bytes) throws IOException
    {
        int global_offset = block_id * blocksize + block_offset;
        int new_offset = global_offset + bytes;

        seekFromStart(new_offset);
    }

    public int read() throws IOException
    {
        byte array[] = new byte[1];

        try
        {
            int forward;
            forward = read(array, 0, 1);
            if (forward >= 0)
                abs_offset += forward;
            else
                return -1;
            /*
            System.out.println("read: '" + new String(array, 0, 1) + "'");
            */
            /*System.out.println("read: '" + array[0] + "'");*/
        } catch (IOException e)
        {
            return -1;
        }

        return (int) array[0];
    }

    public void openIndex(int i)
    {
        block_id = i;

        String name;
        name = basename + int2char(block_id);
        /*
        System.out.println("Opening file: " + name); */


        in = getClass().getResourceAsStream(name);
        block_offset = 0;
        abs_offset = block_id * blocksize;
        if (useMarks)
        {
            in.mark(blocksize);
            System.out.println("InputStream marked");
        }
    }

    public void openNextIndex()
    {
        block_id += 1;

        openIndex(block_id);
    }

    public int read(byte array[], int offset, int length) throws IOException
    {
        int file_id;
        int array_offset;
        int rest;
        int toread;

        toread = length;
        rest = length;
        array_offset = 0;
        while (rest > 0)
        {
            if (in == null)
                throw new IOException("Out of file bounds");

            int rest_in_block = blocksize - block_offset;
            toread = rest;
            if (toread > rest_in_block)
                toread = rest_in_block;
            /*
            if (rest_in_block <= 1 || block_offset <= 1)
                System.out.println("toread: " +
                        new Integer(toread).toString() +
                        " rest_in_block: " +
                        new Integer(rest_in_block).toString() +
                        " rest: " +
                        new Integer(rest).toString() +
                        " array_offset: " +
                        new Integer(array_offset).toString() +
                        " block_offset: " +
                        new Integer(block_offset).toString());
                        */

            int forward;
            forward = in.read(array, array_offset, toread);
            if (forward > 0)
                abs_offset += forward;
            else if (forward == -1)
                break;

            /* For all next reads */
            block_offset += forward;
            array_offset += forward;
            rest -= forward;
            if (rest > 0)
                openNextIndex();
        }

        return array_offset; /* Length read */
    }
}
